package pteam;
import simulator.Simulator;

public class Link {

  public boolean deadEnd = false;
  public boolean undoing = false;
  public boolean selected = false;
  
  Node beginning;
  int /* (Direction) */ beginningDirection;
  Node end;
  int /* (Direction) */ endDirection;
 
  public Link(Node beginning) {
    this.beginning = beginning;
  }
  
  public int newNode(boolean[] holes) {
    Simulator.out.println("this link: "  + this);
    Node n;
    if(this.undoing){
      n = this.beginning;
    } else {
      n = new Node();
    }

    //final decisions: FORWARD RIGHT BACKWARD LEFT
    Link[] temp = { // left, front, right, back
                    holes[0] ? new Link(n) : null,
                    holes[1] ? new Link(n) : null,
                    holes[2] ? new Link(n) : null,
                    this
                  };
    
    int a=0;
    // back = the opposite (rotated twice) of the direction
    Simulator.out.println((undoing?"u ":"!u ") +a+" ["+temp[0] + "] [" + temp[1] + "] [" + temp[2] + "] [" + temp[3]+"]");
    while(temp[flip(beginningDirection)]  != this){
      Simulator.out.println(a+" ["+temp[0] + "] [" + temp[1] + "] [" + temp[2] + "] [" + temp[3]+"]");
      temp = (Link[]) Tree.rotate(temp);
      a++;
    }
    if(undoing){
      Simulator.out.println("undo is checking for match");
      boolean matching = ((n.north == null) == (temp[0] ==null)) &&
      ((n.east == null) == (temp[1] ==null)) &&
      ((n.south == null) == (temp[2] ==null)) && 
      ((n.west == null) == (temp[3] ==null));
      if(matching){
            temp = new Link[] {n.north, n.east, n.south, n.west};
            Simulator.out.println("Verified");
      }else{
         Simulator.out.println("FAILED, sensor data doesn't match, so this isn't the same juction");
        return Tree.FORWARD;
      }
    }
    if(!Tree.current.undoing){
      n.north = temp[0];
      if(n.north != null && n.north != this) n.north.beginningDirection = Tree.NORTH;
      n.east = temp[1];
      if(n.east != null && n.east != this) n.east.beginningDirection = Tree.EAST;
      n.south = temp[2];
      if(n.south != null && n.south != this) n.south.beginningDirection = Tree.SOUTH;
      n.west = temp[3];
      if(n.west != null && n.west != this) n.west.beginningDirection = Tree.WEST;
    }
    int choice = beginningDirection;
    
      int j = RangeFinderAnalysis.rotateDirection(beginningDirection, true);
      //RIGHT
      if(temp[j] != null  && !temp[j].deadEnd && !temp[j].selected) {
          choice = j;
      } else {
        j = RangeFinderAnalysis.rotateDirection(beginningDirection, false);
        //LEFT
        if(temp[j] != null  && !temp[j].deadEnd && !temp[j].selected) 
          choice = j;
        else {    
          // Straight
          j = flip(beginningDirection);
          if(temp[j] != null  && !temp[j].deadEnd && !temp[j].selected)
            choice = j;
        }
      }

    Simulator.out.println("beginningDirection = " + beginningDirection);
    Simulator.out.println("choice = " + choice);
    Simulator.out.println("Node printout : \n" + n);

    if(throughNode(n)) {
       Simulator.out.println("through node detected; skipped");
       return Tree.FORWARD;
    }
    
    if(choice == beginningDirection) {
      //Time to undo
      
//      this.deadEnd = true;
//      this.selected = false;
//      this.undoing=true; 
//      
      for(int i=Tree.NORTH; i<=Tree.WEST; i++) {
        if(n.get(i) != null && n.get(i).selected) {
          int direction = toRelative(flip(i));
          //n.get(i).beginningDirection = flip(i);
          Tree.current = n.get(i);
          System.out.println("i = " +i +" or could be: " +flip(i) +"$");
          Tree.current.beginningDirection = flip(i);
          Tree.current.selected = false;	
          this.deadEnd = true; 
          Tree.current.undoing=true;  
          
          return direction;
        }
      }

       Simulator.out.println("going backward (SPECIAL CASE)");
       Tree.current.beginningDirection = flip(beginningDirection);
      return Tree.BACKWARD; 
    } else { // not undoing, not a through node
      n.get(choice).selected = true; 
      int decision = toRelative(choice);
      Tree.current =  n.get(choice);
      end = n;
      endDirection = choice; 
      return decision;
    }
  }
  
  public int flip(int i) {
    return RangeFinderAnalysis.rotateDirection(
    		RangeFinderAnalysis.rotateDirection(
    				i, true), true);
  }

  public String toString() {
    return (deadEnd?"(deadEnd)":"(       )") + " " + (undoing?"(undoing)":"(       )") + " " + (selected?"(selected)":"(         )");
  }

  public int toRelative(int absdir) {
      Simulator.out.println("absolute: " +absdir + "beginningDir: " +  beginningDirection);
      if(RangeFinderAnalysis.rotateDirection(absdir, true) == (beginningDirection)) { 
        System.out.println("LEFT");
        return Tree.LEFT;
      } else if(RangeFinderAnalysis.rotateDirection(absdir, false) == (beginningDirection)) { 
        Simulator.out.println("RIGHT");
        return Tree.RIGHT;  
      } else if(absdir != (beginningDirection)) {
        Simulator.out.println("FORWARD");
        return Tree.FORWARD;
      } else {
        Simulator.out.println("BACKWARD");
        return Tree.BACKWARD;
      }   
  }
  
  public boolean throughNode(Node n){
    return ((n.north == null && n.south == null) && (n.east != null && n.west != null)) || 
           ((n.east == null && n.west == null) && (n.north != null && n.south != null));
  }
}